package com.cilico;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Stack;
import java.util.Vector;

import org.apache.http.util.ByteArrayBuffer;

import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;

import com.cilico.citylist.AGPS;
import com.cilico.components.Alert;
import com.cilico.components.AtomParser;
import com.cilico.components.ChannelRepository;
import com.cilico.components.Component;
import com.cilico.components.CssStyle;
import com.cilico.components.Div;
import com.cilico.components.POI;
import com.cilico.components.PoiListSelection;
import com.cilico.components.PoiRepository;
import com.cilico.components.PoiSelection;
import com.cilico.components.WaitDialog;
import com.cilico.utils.Constant;
import com.cilico.utils.ConstantRepository;
import com.cilico.utils.HttpManager;
import com.cilico.utils.PackageManagerAndroid;
import com.cilico.utils.Utils;
import com.cilico.view.BaseView;
import com.cilico.view.ChannelEntity;
import com.cilico.view.DetailView;
import com.cilico.view.DisplayPoi;
import com.cilico.view.HelpView;
import com.cilico.view.LoginView;
import com.cilico.view.MainView;
import com.cilico.view.SplashScreen;
import com.cilico.view.UserManager;

public class Mid {
	BaseView activity_; // 上下文
	private static Mid mid_;  // 所有对象管理器
	public HttpManager hm_; // 网络管理
	public PackageManagerAndroid pm_; // 数据库
	public UserManager um_; // 用户管理
	public AtomParser parser_; // 解析器
	DetailView detailView_; // 详情页面
	public Constant constant_; // 常量集
	public ChannelRepository topChannelRepo_; // 存放二级菜单列表
	public ChannelRepository belowChannelRepo_;
	public ChannelRepository channelRepo_;// 保存九宫格频道
	public PoiRepository poiRepo_;// 保存poi列表 现在只用到一个
	public PoiListSelection poiListSelection_;// 与PoiRepository近似
	public WaitDialog waitDialog_; // 加载框
	public ChannelEntity channelEntity_;
	Alert alert_; // 提示框
	public static HashMap<String, Object> saveProperty_; // 程序保存变量集合，专门针对有"truesave"属性的控件作相关保存
	public static HashMap<String, Object> savePropertyTemp_; // 程序保存变量集合，专门针对有"save"属性的控件作相关保存
	public static final int LAUNCHER_SCREEN = 0;  // 视图索引-闪屏
	public static final int MAIN_VIEW = 1;    // 视图索引-九宫格
	public static final int LOGIN_VIEW = 2;       // 视图索引-登录
	public static final int DETAIL_VIEW = 3;  // 视图索引-详情页面
	public static final int CHANNEL_LIST = 4;     // 视图索引-频道列表
	public static final int MAP_VIEW = 5;         // 视图索引-地图
	public static final int HELP_VIEW = 6 ;       // 视图索引-帮助
	public Stack<String[]> stackWindows_; // 页面报文堆栈，用于返回上一页面。在跳到下一页面前，我们把当前页面压栈,当从一个页面返回时，我们对它执行退栈操作。注意：如果对话框中有失败的请求，也会执行退栈操作
	public boolean istoMain_;// true应跳转到九宫格
	boolean midletStarted_;
	String currentFilePath_ = "";
	public String midletVersion_; // 软件版本，用于提示更新
	public boolean updateMode_; //true时应检查并提示版本更新
	int foundUpdate_;
	private final int updateAlertOk_ = 1;
	private final int updateAlertCancel_ = 2;
	public HashMap<String, ArrayList<Component>> cacheDivs; // 保存缓存的DIV,由于部分页面中的DIV过长, 反复解析耗时过长，所以按需将其保存，跳过解析
	public HashMap<String, CssStyle> cacheDivStyles_; // 缓存DIV样式
	public static AGPS agps_; // 当前位置信息

	/**
	 * 创建一个新Mid对象
	 */
	public Mid(BaseView activity) {
		mid_ = this;
		try {
			activity_ = activity;
			PackageManager pm = activity.getPackageManager();
			PackageInfo pi = pm.getPackageInfo("com.cilico", PackageManager.GET_ACTIVITIES);
			midletVersion_ = pi.versionName;
			stackWindows_ = new Stack<String[]>();
			updateMode_ = true;
			foundUpdate_ = 0;
			midletStarted_ = false;
			ConfigManager.makeUserAgent("", midletVersion_);
			if (alert_ == null)
				alert_ = new Alert();
		} catch (NameNotFoundException e) {
			Utils.printException(e);
		}
	}

	/**
	 * 静态方法,返回一个Mid对象
	 */
	public static Mid getInstance() {
		return mid_;
	}

	/**
	 * 闪屏时调用，该处抛出的所有异常都会被捕获
	 */
	public void initApp(SplashScreen splashView) throws Exception {
		// 不要多次初始化
		if (hm_ == null)
			hm_ = new HttpManager(this);
		if (pm_ == null)
			pm_ = new PackageManagerAndroid(splashView);
		pm_.permDB_.init();
		if (um_ == null)
			um_ = new UserManager(this, hm_, pm_, splashView);
		um_.loadState();
		if (parser_ == null)
			parser_ = new AtomParser(this);
		if (constant_ == null)
			constant_ = new Constant(activity_);
		if (channelRepo_ == null)
			channelRepo_ = new ChannelRepository(this);
		if (topChannelRepo_ == null)
			topChannelRepo_ = new ChannelRepository(this);
		if (belowChannelRepo_ == null)
			belowChannelRepo_ = new ChannelRepository(this);
		if (channelEntity_ == null)
			channelEntity_ = new ChannelEntity(this);
		if (waitDialog_ == null)
			waitDialog_ = new WaitDialog(this);
		if (poiRepo_ == null)
			poiRepo_ = new PoiRepository(this);
		pm_.initStorage();
		
		ConfigManager.initManager(activity_);
		
		if (null == saveProperty_) {
			String save = this.pm_.SAVEPROPERTYDB_.get(PackageManagerAndroid.SAVEPROPERTY_DB);
			saveProperty_ = Utils.getSavePropoerty(save);
			if (null == saveProperty_)
				saveProperty_ = new HashMap<String, Object>();
		}
		if (null == savePropertyTemp_) {
			savePropertyTemp_ = new HashMap<String, Object>();
		}

		if (!um_.userLoggedIn()) {
			splashView.setErrMsg("badcookie");
		} else {
			try {
				restoreRmsStates(null, null, splashView);
			} catch (Exception e) {
				Utils.printOutToConsole("Mid-initApp:" + e.toString());
				// It's ok if we do not get a location. We'll continue with the rest.
				splashView.setErrMsg(e.getMessage());
			}
		}
		// We use this to check if we need to show an alert screen from background login task.
		midletStarted_ = true;
	}

	/**
	 * 更新提示框处理
	 * 
	 * @param command the Command that ws invoked
	 * @param displayable the Displayable on which the command was invoked
	 */
	public void commandAction(BaseView activity, int commandType) {
		final BaseView activityTemp = activity;
		// 确定更新，跳转到网页下载
		if (commandType == updateAlertOk_) {
			try {
				foundUpdate_ = 0;
				versionUpdate(true, activity);
			} catch (Exception ex) {
				Utils.printOutToConsole("Mid-commandAction-ex:" + ex.toString());
			}
		} else if (commandType == updateAlertCancel_) {
			// 取消更新,继续显示下一页
			updateMode_ = false;
			foundUpdate_ = 0;
			waitDialog_.addFgTask(activity_, new WaitDialog.Task(0) {
				public void run(WaitDialog dlg) {
					if (um_.userLoggedIn())
						restoreRmsStates(dlg, this, null);
				}

				public void onSuccess(WaitDialog dlg) {
					handleLoginSuccess(activityTemp);
					super.onSuccess(dlg);
				}

				public void onFailure(WaitDialog dlg) {
					handleLoginFailure(getErrMsg());
					super.onFailure(dlg);
				}
			}, false);
			waitDialog_.setText("载入首页");
		}
	}

	/*
	 * 打开网页下载最新版本。用户来到这里，说明他的身份一定合法。
	 */
	private final void versionUpdate(boolean updatemode, BaseView bv) throws Exception {
		activity_ = bv;
		if (updatemode) {
			try {
				StringBuffer buf = new StringBuffer();
				buf.append(um_.downloadCode_); // the download include the host address.
				buf.append("?a=");
				buf.append(Utils.escapeURIComponent(ConfigManager.APP_USERAGENT));
				Utils.printOutToConsole("buf:" + buf.toString());
				this.dialWeb("http://wap.95559.com.cn", bv);
			} catch (Exception ex) {
				Utils.printOutToConsole("Mid-versionUpdate-ex:" + ex.toString());
			}
		}
	}

	private void getUpdateFile(final String string, final BaseView bv) {
		try {
			Runnable r = new Runnable() {
				public void run() {
					try {
						getDataSource(string, bv);
						bv.exitApplication();
					} catch (Exception e) {
						Utils.printOutToConsole("Mid-getFile-e:" + e.toString());
					}
				}

			};
			new Thread(r).start();
		} catch (Exception e) {
			Utils.printException(e);
		}
	}

	private void getDataSource(String strPath, BaseView bv) throws IOException {
		// 取得URL
		URL urlTemp = new URL(strPath);
		// 创建连接
		URLConnection conn = urlTemp.openConnection();
		conn.connect();
		// 下载文件
		InputStream is = conn.getInputStream();
		if (null == is) {
			throw new RuntimeException("stream is null");
		}
		// 创建临时文件
		File fileTemp = File.createTempFile("update", ".apk");
		// 将文件写入暂存盘
		FileOutputStream fos = new FileOutputStream(fileTemp);
		byte buf[] = new byte[128];
		do {
			int numread = is.read(buf);
			if (numread <= 0) {
				break;
			}
			fos.write(buf, 0, numread);
		} while (true);
		// 打开文件进行安装
		openFile(fileTemp, bv);
		try {
			is.close();
		} catch (Exception e) {
			Utils.printOutToConsole("Mid-getDataSource-e:" + e.toString());
		}
	}

	private void openFile(File fileTemp, BaseView bv) {
		Intent intent = new Intent();
		intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		intent.setAction(android.content.Intent.ACTION_VIEW);
		String type = getMIMEType(fileTemp);
		intent.setDataAndType(Uri.fromFile(fileTemp), type);
		bv.startActivity(intent);
	}

	private String getMIMEType(File fileTemp) {
		String type = "";
		String fName = fileTemp.getName();
		String end = fName.substring(fName.lastIndexOf(".") + 1, fName.length()).toLowerCase();
		if (end.equals("m4a") || end.equals("mp3") || end.equals("mid") || end.equals("xmf") || end.equals("ogg") || end.equals("wav")) {
			type = "audio";
		} else if (end.equals("3gp") || end.equals("mp4")) {
			type = "video";
		} else if (end.equals("jpg") || end.equals("gif") || end.equals("png") || end.equals("jpeg") || end.equals("bmp")) {
			type = "image";
		} else if (end.equals("apk")) {
			type = "application/vnd.android.package-archive";
		} else {
			type = "*";
		}
		if (end.equals("apk")) {

		} else {
			type += "/*";
		}
		return type;
	}

	/**
	 * This is always called after successful user login to restore RMS states. Note that UserManager states have been
	 * restored earlier in order to validate user login.
	 */
	private final boolean restoreRmsStates(WaitDialog dlg, WaitDialog.Task task, SplashScreen splashScr) {
		try {
			if (!pm_.isInitStorage_)
				pm_.initStorage();
		} catch (Exception ex) {
			Utils.printOutToConsole("Mid-restoreRmsStates-ex:" + ex.toString());
		}
//		boolean found = lm_.loadState(pm_, um_);
		boolean found =  false;
		return found;
	}


	public DetailView getDetailView(BaseView activity) {
		if (activity instanceof DetailView) {
			detailView_ = (DetailView) activity;
		} else {
			detailView_ = null;
		}
		return detailView_;
	}

	public void handleLoginFailureAgain(BaseView activity) {
		if (activity instanceof LoginView) {
			LoginView loginView = (LoginView) activity;
			loginView.removeAll();
			loginView.populate((POI) BaseView.mid_.poiRepo_.peekActionPoi());
			Utils.addManagerAndSetTop(activity);
		} else {
			Intent intent = new Intent();
			intent.setClass(activity, LoginView.class);
			activity.startActivity(intent);
			WaitDialog.Task.cancelProgressBar(activity);
			activity.finish();
		}
	}

	public void handleLoginSuccess(BaseView activity) {
		if (foundUpdate_ != 0) {
			// 版本更新提示
			versionUpdateAlert(activity, foundUpdate_);
		} else {
			// 页面跳转
			if (um_.channelId_ == null && um_.checkInfo_.length() > 0) {
				// 九宫格，显示预留信息
				gotoMainView(activity, true);
			} else if (um_.isShowLaunchS_) {
				// 九宫格，不显示预留信息
				gotoMainView(activity, false);
			} else {
				// 地图
				handleLoadMapSuccess();
			}
		}
	}

	void versionUpdateAlert(BaseView activity, int forceUpdate) {
		final BaseView activityTemp = activity;
		Builder builder = new AlertDialog.Builder(activityTemp);
		builder.setTitle("提示").setMessage("欢迎您回来，我们增加了新的服务功能，希望为您提供更好的服务。 请按确定进行更新!")
		.setCancelable(true).setPositiveButton("确 定", new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						commandAction(activityTemp, updateAlertOk_);
					}
				}).setNegativeButton("忽略", new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						commandAction(activityTemp, updateAlertCancel_);
					}
				});
		if (!activity.isFinishing()) {
			builder.show();
		}
	}

	/**
	 * 跳转到地图页面
	 */
	void handleLoadMapSuccess() {
		
	}

	/**
	 * 处理未登录/初始化失败
	 * @param activity
	 * @param errmsg_
	 */
	public void handleLoginFailure(BaseView activity, String errmsg_) {
		try {
			activity_ = activity;
			um_.resetLoginAndKeys();
			if (errmsg_.equals("badcookie")) {
				// 重新发起ClientHello，跳转到登录页面
				gotoLoginView(activity);
			} else if (errmsg_.equals("signup")) {
				alert(activity, "密码错误，请重试！", LOGIN_VIEW, false);
			} else if (errmsg_.equals("wrongpin")) {
				alert(activity, "密码错误，请重试！", LOGIN_VIEW, false);
			} else {
				alert(activity, errmsg_, LOGIN_VIEW, true);
			}
		} catch (Exception ex) {
			alert(activity, ex.getMessage(), LOGIN_VIEW, true);
		}
	}

	public void alert(BaseView activity, String str, boolean isSendLog) {
		if (null != hm_ && hm_.errorType != null && hm_.errorType.equalsIgnoreCase("timeout")) {
			parserLoginMessage(activity_, Utils.unescapeHTML(hm_.errorContent));
			handleLoginFailureAgain(activity);
		} else {
			activity_ = activity;
			alert_.infoAlert(activity_, this, str, isSendLog);
		}
	}

	public void alert(BaseView activity, String str, int nextScreen, boolean isSendLog) {
		// 此处原来有压棧操作，在用户做“发送错误报告”时将弹栈。
		// 但当用户选择“取消”操作时，无弹栈操作，这将引发后面返回操作之后界面显示出错。
		// 现已修改处理逻辑，不再压棧；未知是否会引发其他问题
		// pushDisplayable(nextScreen, null, null);
		if (null != hm_ && hm_.errorType != null && hm_.errorType.equalsIgnoreCase("timeout")) {
			parserLoginMessage(activity_, Utils.unescapeHTML(hm_.errorContent));
			handleLoginFailureAgain(activity);
		} else {
			activity_ = activity;
			if (str.startsWith("alert:")) {
				str = str.substring(6);
				String[] strArray = str.split("#");
				if (strArray != null) {
					String title = null;
					String info = null;
					String cmdStr = null;
					String url = null;
					for (int i = 0; i < strArray.length; i++) {
						switch (i) {
						case 0:
							title = strArray[i];
							break;
						case 1:
							info = strArray[i];
							break;
						case 2:
							cmdStr = strArray[i];
							break;
						case 3:
							url = strArray[i];
							break;
						}
					}
					alert_.actionInfoAlert(activity, this, title, info, cmdStr, url);
				} else {
					alert_.infoAlert(activity, this, "未能获取到数据！", isSendLog);
				}
			} else {
				alert_.infoAlert(activity, this, str, isSendLog);
			}
		}
	}

	/**
	 * 跳转到登录页面
	 * @param activity
	 */
	public void gotoLoginView(final BaseView activity) {
		try {
			um_.clientHello(activity);
		} catch (Exception e) {
			Utils.printException(e);
		}finally{
			//初次联网失败视为URL地址不对或者网络不通
		}
	}

	private String createLoginBody() {
		String body = "&Version=" + "AD-UMP-" + Mid.this.midletVersion_ + "-080901" + "&Randomkey=123456";
		// 对加过密后的消息进行两次URI编码
		body = "mk=".concat(Utils.escapeURIComponent(body));
		return body;
	}

	public void parserLoginMessage(BaseView bv, String xml) {
		try {
			if (null == BaseView.mid_.parser_)
				BaseView.mid_.parser_ = new AtomParser(BaseView.mid_);
			BaseView.mid_.parser_.setOnePOIProperty(AtomParser.parseOnePOI_, bv);
			android.util.Xml.parse(xml, BaseView.mid_.parser_);
			BaseView.mid_.poiRepo_.pushActionPoi(BaseView.mid_.parser_.getOnePOI());
			BaseView.mid_.poiRepo_.channel_ = BaseView.mid_.parser_.getChannel();
		} catch (Exception e) {
			Utils.printOutToConsole(e.toString());
		}
	}

	public void gotoView(int view, String id, BaseView bv) {
		String[] lastView = new String[] { "" + view, id };
		gotoView(bv, lastView);
	}

	void gotoView(BaseView activity, String[] lastView) {
		if (lastView == null) {
			gotoMainView(activity, false); // we always go to main view as default.
			return;
		}
		int view = Integer.parseInt(lastView[0]);
		switch (view) {
		case LOGIN_VIEW:
			gotoLoginView(activity);
			break;
		case HELP_VIEW:
			gotoHelpView(activity);
			break;
		case MAIN_VIEW:
			gotoMainView(activity, false);
			break;
		case DETAIL_VIEW:
			gotoDetailView(activity, true, false, 0, false);
			break;
		default:
			gotoMainView(activity, false); // 默认跳到MainView页面
			break;
		}
	}

	public final void gotoDetailView(BaseView activity, boolean showTab, boolean isRunChangeChannel, int detailType, boolean abOpenDetail) {
		if (activity instanceof DetailView) {
			if (abOpenDetail) {
				openDetailAbsolutely(activity, showTab, isRunChangeChannel, detailType, abOpenDetail);
			} else {
				DetailView detailV = (DetailView) activity;
				detailV.detailType_ = detailType;
				detailV.showTab(showTab);
				detailV.show();
				Utils.addManagerAndSetTop(detailV);
			}
		} else {
			openDetailAbsolutely(activity, showTab, isRunChangeChannel, detailType, abOpenDetail);
		}
	}

	/**
	 * 完全重新打开详细界面
	 * 
	 */
	public void openDetailAbsolutely(final BaseView activity, final boolean showTab, final boolean isRunChangeChannel, final int detailType, final boolean abOpenDetail) {
		activity.runOnUiThread(new Runnable() {
			public void run() {
				// 如果状态栏存在且已显示，则在完全重新进入详细界面时将其隐藏
				if (null != activity.statusBar_) {
					if (activity.statusBar_.isShown())
						activity.statusBar_.setVisibility(View.GONE);
				}
				Intent intent = new Intent();
				intent.setClass(activity, DetailView.class);
				// 定义值传递对象
				Bundle bundle = new Bundle();
				bundle.putBoolean("showTab", showTab);
				bundle.putBoolean("isRunChangeChannel", isRunChangeChannel);
				bundle.putInt("detailType", detailType);
				bundle.putCharSequence("channelID", channelRepo_.getCurrentChannelID());
				intent.putExtras(bundle);
				activity.startActivity(intent);
				activity.finish();
			}
		});
	}

	public void gotoMainView(final BaseView activity, boolean isShowMessage) {
		try {
			// 直接清空隐藏域和本地栈集合
			activity.delContentStack();
			if (activity.tabBar_ != null)
				activity.removeAll();
			parser_.dispose();
			parser_ = null;
			parser_ = new AtomParser(this);
			activity.dispose();
		} catch (Exception e) {
			Utils.printOutToConsole("清空资源时的警告，可以忽略：" + e.getMessage());
		}

		pushDisplayable(MAIN_VIEW, null, Constant.MAIN_TITLE);
		if (!activity.isFinishing()) {
			Intent intent = new Intent();
			// 定义值传递对象
			Bundle bundle = new Bundle();
			bundle.putBoolean("isShowMessage", isShowMessage);
			intent.putExtras(bundle);
			intent.setClass(activity, MainView.class);
			activity.startActivity(intent);
			activity.finish();
		}
	}

	void gotoHelpView(BaseView bv) {
		Intent intent = new Intent();
		intent.setClass(bv, HelpView.class);
		bv.startActivity(intent);
	}


	String peekTopTitle() {
		String title = null;
		String[][] view = null;
		if (stackWindows_ != null && !stackWindows_.empty()) {
			view = new String[stackWindows_.size()][3];
			try {
				for (int i = 0; i < view.length; i++) {
					view[i] = this.popDisplayable();
					if (view[i][2] != null) {
						for (int j = view.length - 1; j >= 0; j--) {
							if (view[j] != null) {
								if (!(view[j][0] == null && view[j][1] == null && view[j][2] == null))
									this.pushDisplayable(Integer.parseInt(view[j][0]), view[j][1], view[j][2]);
							}
						}
						title = view[i][2];
						break;
					}
				}
			} catch (Exception ex) {
			}
		}
		return title;
	}

	public void removeDisplayable() {
		if (stackWindows_ != null) {
			stackWindows_.removeAllElements();
		}
	}

	/**
	 * Removes the object at the top of this stack and returns that object as the value of this function.
	 */
	public String[] popDisplayable() {
		String[] view = null;
		if (stackWindows_ != null && !stackWindows_.empty()) {
			try {
				view = (String[]) stackWindows_.pop();
				Utils.printOutToConsole("########popDisplayable() out view  = " + view[0] + ", id = " + view[1] + ", title = " + view[2]);
			} catch (Exception ex) {
			}
		}
		return view;
	}

	/**
	 * if a view diferrent the view of the top of this stack, we will push it.
	 */
	public final void pushDisplayable(int view, String id, String title) {
		if (stackWindows_ != null) {
			String[] top = peekDisplayable();
			int topView = -1;
			try {
				if (top != null)
					topView = Integer.parseInt(top[0]);
			} catch (Exception ex) {
			}
			if (top != null) {
				if (topView != view) {
					stackWindows_.push(new String[] { "" + view, id, title });
					Utils.printOutToConsole("####### pushDisplayable() into view = " + view + ", id = " + id + ", title = " + title);
				} else {
					if (id != null) {
						if (!id.equals(top[1])) {
							stackWindows_.push(new String[] { "" + view, id, title });
							Utils.printOutToConsole("######## pushDisplayable() into view = " + view + ", id = " + id + ", title = " + title);
						}
					} else if (top[1] != null) {
						stackWindows_.push(new String[] { "" + view, id, title });
						Utils.printOutToConsole("###### pushDisplayable() into view = " + view + ", id = " + id + ", title = " + title);
					}
				}
			} else {
				stackWindows_.push(new String[] { "" + view, id, title });
				Utils.printOutToConsole("###### pushDisplayable() into view = " + view + ", id = " + id + ", title = " + title);
			}
		}
	}

	/**
	 * Looks at the object at the top of this stack without removing it from the stack.
	 */
	public String[] peekDisplayable() {
		String[] view = null;
		if (stackWindows_ != null && !stackWindows_.empty()) {
			String[][] temp = new String[stackWindows_.size()][];
			stackWindows_.copyInto(temp);
			for (int i = 0; i < temp.length; i++) {
				Utils.printOutToConsole("####### peekDisplayable() see stack view  " + i + " = " + temp[i][0] + ", id = " + temp[i][1] + ", title = " + temp[i][2]);
			}
			try {
				view = (String[]) stackWindows_.peek();
			} catch (Exception ex) {
			}
		}
		return view;
	}

	/**
	 * Download and cache thumbnail image in this POI.
	 */
	public void downloadImage(String imgUrl, int index, int width, int height, Vector<Bitmap> images) throws Exception {
		Bitmap image = null;
		StringBuffer url = new StringBuffer(imgUrl);
		
		if (imgUrl != null && !imgUrl.contains("http://")) {
			url = url.delete(0, url.length());
			url.append(ConfigManager.SERVER_URI);
			url.append(ConfigManager.GET_PIC_URI);
			url.append("url=");
			url.append(Utils.escapeURIComponent(imgUrl));
			url.append("&w=");
			url.append(width);
			url.append("&h=");
			url.append(height);
		}
			Utils.printOutToConsole("download image : url=" + url + " index=" + index);
			try {
				boolean isExists = compare(imgUrl);
            	//(如果缓存过程中出错，是否会导致以后读取都会出错，此外是否每次退出程序清除缓存的图片)
            	if (isExists == false){ //没有缓存
//            		 image = getImage(imgUrl);
            		 ByteArrayOutputStream imageBuffer = new ByteArrayOutputStream(1024);
    				 hm_.read(url.toString(), imageBuffer, null);
    				 byte[] imageBytes = imageBuffer.toByteArray();
    				 imageBuffer.close();
    				 image = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
    				 if (image == null) {
    					 imageBytes = Utils.gunzip(imageBytes);
    					 image = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
    				 }
    				 if (null != image){
                         saveImage(imgUrl, Bitmap2Bytes(image));
    				 }
    				 images.insertElementAt(image, index);
            	} else{//该图片已经 存在缓存文件中
            		 try {
						 byte[] data = readImage(imgUrl);
						 image = BitmapFactory.decodeByteArray(data, 0, data.length);
						 if (null != image){
							 images.insertElementAt(image, index);
						 }
					} catch (Exception e) {
						image = getImage(imgUrl);
	           			saveImage(imgUrl, Bitmap2Bytes(image));
	           			images.insertElementAt(image, index);
	           			e.printStackTrace();
					}
            	}
			} catch (Exception e) {
				// images.insertElementAt(Utils.createImageLoadFail(),
				Utils.printOutToConsole("Mid-downloadImage-e:" + e.toString());
//	            image = null;
//	            if(image == null){
//	            	image = ConstantRepository.decodeBitmap(activity_.getResources(), R.drawable.nopicture);
	            	images.insertElementAt(null, index);
//	            }
				throw e;
			} catch (OutOfMemoryError oe) {
				// images.insertElementAt(Utils.createImageLoadFail(),
				Utils.printOutToConsole("Mid-downloadImage-oe:" + oe.toString());
				throw oe;
			}
	}

	/**
     * 下载图片
     */
    public void downloadImageRemote(String imgUrl, int index, Vector<Bitmap> images) throws Exception {
        Bitmap image = null;
        if (imgUrl != null) {
            try {
            	Utils.printOutToConsole("imgUrl = " + imgUrl);
            	if(imgUrl.trim().length() > 0 && !(imgUrl.toLowerCase().indexOf("http://") != -1 || imgUrl.toLowerCase().indexOf("lp://") != -1 || imgUrl.toLowerCase().indexOf("https://") != -1)) {
    				//本地取图
            		int mThumbId = Utils.getResourceByReflect(imgUrl.substring(0, imgUrl.indexOf(".")));
    				image = BitmapFactory.decodeResource(activity_.getResources(), mThumbId);
    				images.insertElementAt(image, index);
            	} else {
            		//网络取图
            		boolean isExists = compare(imgUrl);
            		//(如果缓存过程中出错，是否会导致以后读取都会出错，此外是否每次退出程序清除缓存的图片)
            		if (isExists == false){//没有缓存
            			image = getImage(imgUrl);
            			if (image != null){
            				images.insertElementAt(image, index);
                			 saveImage(imgUrl, Bitmap2Bytes(image));
            			} else{
            				images.insertElementAt(null, index);
            			}
            		} else{//该图片已经 存在缓存文件中
            			try {
							byte[] data = readImage(imgUrl);
							image = BitmapFactory.decodeByteArray(data, 0, data.length);
							if (null != image){
								images.insertElementAt(image, index);
							}
						} catch (Exception e) {
							// TODO: handle exception
							image = getImage(imgUrl);
            				saveImage(imgUrl, Bitmap2Bytes(image));
            				images.insertElementAt(image, index);
						}
            		}
            	}
            } catch (Exception e) {
                // images.insertElementAt(Utils.createImageLoadFail(),
            	Utils.printOutToConsole("Mid-downloadImage-e:" + e.toString());
                images.insertElementAt(null, index);
                throw e;
            } catch (OutOfMemoryError oe) {
                // images.insertElementAt(Utils.createImageLoadFail(),
            	Utils.printOutToConsole("Mid-downloadImage-oe:" + oe.toString());
                throw oe;
            }
        }
    }
    
    /**
     * 将图片以文件的形式保存下来
     * @param URL
     * @param data
     * @throws IOException
     */
	public void saveImage(String URL, byte[] data) throws IOException {
		String name = mixHashStr(URL);
		String path = getFileDir(activity_);
		String pathParent = path.substring(0, path.indexOf("images"));
		saveData(path, name, data);
		// 只保存50张图片，多余则删除
		File file = new File(pathParent);
		File[] files = file.listFiles();
		int len = files.length;
		if (len > 100){
			for (int i = 50; i < len; i++) {
				if (files[i].getName().startsWith("images")){
					files[i].delete();
				}
			}
		}
	}
	
	public void saveData(String path, String fileName, byte[] data)throws IOException {
		File file = new File(path + fileName);
		if (!file.exists()) {
			file.createNewFile();
		}
		FileOutputStream outStream = new FileOutputStream(file);
		outStream.write(data);
		outStream.close();
    }
	
    
    
    /**
     * 创建目录
     * @param context
     * @return  文件保存的目录
     */ 
    public static String getFileDir(Context context) {
		String filePath;
		boolean hasSDCard = android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
		//如果已插入SD卡，在SD卡创建临时文件
		if (hasSDCard) {
			filePath = Environment.getExternalStorageDirectory() + "/temp/images";
		} else {
		//没有则在手机自带存储空间创建
			filePath = context.getCacheDir().getAbsolutePath() + "/temp/images";
		}
		File file = new File(filePath);
		if (!file.exists()) {
			file.mkdirs();
		} 
		return filePath;
	} 
    
    
    
    /**
     * 把Bitmap转Byte数组
     * @param bm
     * @return
     */
	public byte[] Bitmap2Bytes(Bitmap bm) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
		return baos.toByteArray();
	}
	
	/** 
	 * 根据文件名读取图片
	 * @param filename
	 * @return
	 * @throws IOException
	 */
	public byte[] readImage(String filename) throws IOException {
		String name = mixHashStr(filename);
		byte[] tmp = readData(getFileDir(activity_), name);
		return tmp;
	}
	
	public byte[] readData(String path, String name) throws IOException {
		ByteArrayBuffer buffer = null;
		String paths = path + name;
		File file = new File(paths);
		if (!file.exists()) {
			return null;
		}
		InputStream inputstream = new FileInputStream(file);
		buffer = new ByteArrayBuffer(1024);
		byte[] tmp = new byte[1024];
		int len;
		while (((len = inputstream.read(tmp)) != -1)) {
			buffer.append(tmp, 0, len);
		}
		inputstream.close();
		return buffer.toByteArray();
	}
	
    public long mixHash(String str) {
		long hash = str.hashCode();
		hash <<= 32;
		hash |= FNVHash1(str);
		return hash;
	}

	public String mixHashStr(String str) {
		return Long.toHexString(mixHash(str));
	}

	public static int FNVHash1(String data) {
		final int p = 16777619;
		int hash = (int) 2166136261L;
		for (int i = 0; i < data.length(); i++)
			hash = (hash ^ data.charAt(i)) * p;
		hash += hash << 13;
		hash ^= hash >> 7;
		hash += hash << 3;
		hash ^= hash >> 17;
		hash += hash << 5;
		return hash;
	}
	
	/**
	 * 根据图片的url判断 图片文件是否存在缓存中
	 * @param url
	 * @return
	 */
	public boolean compare(String url) {
		String name = mixHashStr(url);
		String paths = getFileDir(activity_) + name;
		File file = new File(paths);
		if (!file.exists()) {
			return false;
		}
		return true;
	}
    
	/**
	 * 读取字节流
	 * @param inStream
	 * @return
	 * @throws Exception
	 */
    public byte[] readStream(InputStream inStream) throws Exception{
    	ByteArrayOutputStream outstream = new ByteArrayOutputStream();
    	byte[] buffer = new byte[1024];
    	int len = -1;
    	while((len = inStream.read(buffer)) != -1){
    		outstream.write(buffer, 0, len);
    	}
    	outstream.close();
    	inStream.close();
    	return outstream.toByteArray();
    }
    
    /**
     * 字节流转换成图片
     * @param urlPath
     * @return
     * @throws Exception
     */
    public Bitmap getImage(String urlPath) throws Exception {
    	String host = null;
		String query = null;
    	if (HttpManager.connectType_ == 1) {
    		// CMWAP
    			host = urlPath;
    			int startIndex = host.indexOf("//") + 2;
    			int endIndex = host.indexOf('/', startIndex);
    			if (endIndex > 0)
    				host = host.substring(startIndex, endIndex);
    			int index = urlPath.indexOf('/', startIndex);
    			query = urlPath.substring(index);
    			urlPath = Utils.wapHost.concat(query);
    	}
    	
    	URL url = new URL(urlPath);
    	Bitmap image = null;
    	HttpURLConnection conn = (HttpURLConnection)url.openConnection();
    	conn.setRequestMethod("GET");
    	if (HttpManager.connectType_ == 1) //CMWAP
    		conn.setRequestProperty("X-Online-Host", host);
    	conn.setConnectTimeout(ConfigManager.TIMECONNECTTIMEOUT);
    	if(conn.getResponseCode() == 200){
    		InputStream in = conn.getInputStream();
    		byte[] data = readStream(in);
        	image = BitmapFactory.decodeByteArray(data, 0, data.length);
        	return image;
    	}
    	return null;
    }
	
	/**
	 * Used by both login forms to process a login request. Both parameters are final, so that they can be accessed by
	 * inner class.
	 */
    public void processLogin(final String host, final String body, final boolean isSignIn, final BaseView bv,final Vector<Component> itemV_) {
		// 解决强制修改密码成功之后返回登录页面显示两个logo的问题
		if (host.indexOf("getui") != -1) {
			while (BaseView.mid_.poiRepo_.actionV_.size() > 0) {
				BaseView.mid_.poiRepo_.popActionPoi();
			}
		}
		activity_ = bv;
		final BaseView activityTemp = bv;
		
		waitDialog_.addFgTask(bv, new WaitDialog.Task(0) {
			public void run(WaitDialog dlg) {
				try {
					int loginStatus = um_.userLogin(host, body, isSignIn, bv, this);
					switch (loginStatus) {
					case UserManager.UM_SIGNUP:
						setErrMsg("signup");
						break;
					case UserManager.UM_WRONGPIN:
						setErrMsg("wrongpin");
						break;
					case UserManager.UM_SOFTWARE_UPDATE:
						foundUpdate_ = 2;
						break;
					case UserManager.UM_SOFTWARE_UPDATE_OPTION:
						foundUpdate_ = 1;
						break;
					case UserManager.UM_SUCCESS:
						dlg.setText(ConstantRepository.getWaitText(ConstantRepository.INIT_MAINVIEW));
						if (um_.userLoggedIn()) {
							restoreRmsStates(dlg, this, null);
						}
						break;
					case UserManager.UM_ERROR_INFO:
						break;
					default:
						setErrMsg("登录失败！未知的响应状态。");
						break;
					}
				} catch (HttpManager.NoGatewayException ex) {
					setErrMsg("无法找到TCP网关。请联系您的运营商询问有关您的手机存取TCP/IP的WAP网关的设定信息。");
				} catch (IOException e) {
					String errMsg = e.getMessage();
					if (errMsg == null)
					    errMsg = "由于网络异常导致登录失败，请重试。" + e.toString();
					setErrMsg(errMsg);
				} catch (NullPointerException e) {
					String errMsg = e.getMessage();
					if (errMsg == null)
					    errMsg = "登录失败，服务器异常，请重试。" + e.toString();  
					setErrMsg(errMsg);
				} catch (Exception e) {
					String errMsg = e.getMessage();
					if (errMsg == null) {
						errMsg = "登录失败，网络异常，请重试。" + e.toString();
					}
					//有可能是数据解析异常
					setErrMsg(errMsg);
				}
			}

			public void onSuccess(WaitDialog dlg) {
				if (isSignIn) {
					if (ConfigManager.TMS_CLEARED_USERINFO) {
						// 此条件表明tms出于某种原因已无客户信息，但是仍在此步骤发送一注册界面信息给客户端
						// 此时客户端应显示注册界面，让用户重新注册
						Utils.saveProperties(bv, itemV_);
						handleLoginFailureAgain(activityTemp);
						ConfigManager.TMS_CLEARED_USERINFO = false;
					} else {
						Utils.saveProperties(bv, itemV_);
						handleLoginSuccess(activityTemp);
					}
				} else {
					// 如果点击按钮的属性名称不为ewp_login_app则重新进入注册界面，表示当前值完成了注册中的某一步
					// 用户点击“用户注册”或者“找回密码”，此时仍用注册界面显示，但把该界面对象加入注册界面栈
					if (mid_.istoMain_){
						handleLoginSuccess(activityTemp);
						mid_.istoMain_ = false;
					} else{
						handleLoginFailureAgain(activityTemp);
					}
				}
				super.onSuccess(dlg);
			}

			public void onFailure(WaitDialog dlg) {
				handleLoginFailure(getErrMsg());
				super.onFailure(dlg);
			}
		}, false);
		waitDialog_.setText(ConstantRepository.getWaitText(ConstantRepository.LOGIN));
	}


	void handleLoginFailure(String errMsg) {
		try {
			if (errMsg.equals("badcookie")) {
				gotoLoginView(activity_);
			} else if (errMsg.equals("signup")) {
				alert(activity_, "密码错误，请重试！", LOGIN_VIEW, false);
			} else if (errMsg.equals("wrongpin")) {
				alert(activity_, "密码错误，请重试！", LOGIN_VIEW, false);
			} else {
				alert(activity_, errMsg, LOGIN_VIEW, true);
			}
		} catch (Exception ex) {
			alert(activity_, ex.getMessage(), LOGIN_VIEW, true);
		}
	}

	public String[] peekDisplayable(int depth) {
		String[] view = null;
		if (stackWindows_ != null && !stackWindows_.empty()) {
			try {
				view = (String[]) stackWindows_.elementAt(stackWindows_.size() - 1 - depth);
			} catch (Exception ex) {
			}
		}
		return view;
	}


	/**
	 *  打开网页操作
	 * @param url
	 * @param bv
	 * @throws Exception
	 */
	public void dialWeb(final String url, BaseView bv) throws Exception {
		if (url.endsWith(".apk")) {
			BaseView.mid_.waitDialog_.showProgressdialog(bv);
			BaseView.mid_.getUpdateFile(url, bv);
		} else {
			bv.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
		}
	}

	void setActivity(BaseView bv) {
		activity_ = bv;
	}


	/**
	 * @param div
	 * @param cssStyle
	 */
	public void appendCacheDiv(Div div) {
		if (div == null) {
			return;
		}
		if (!div.name_.equals("div1")) {
			return;
		}
		if (cacheDivs == null) {
			cacheDivs = new HashMap<String, ArrayList<Component>>();
		}
		if (cacheDivStyles_ == null) {
			cacheDivStyles_ = new HashMap<String, CssStyle>();
		}
		int size = div.childrenAmount();
		if (size <= 0) {
			return;
		}
		ArrayList<Component> views = new ArrayList<Component>();
		for (int i = 0; i < size; i++) {
			try {
				views.add(div.child(i));
			} catch (Exception e) {
				continue;
			}
		}
		cacheDivs.put(div.name_, views);
		cacheDivStyles_.put(div.name_, div.cssStyle_);
	}


	public void getUI(final BaseView activity) {
		final String body = createLoginBody();
		um_.processGetUi(activity, body);
	}

	/**
	 * 重新显示登录界面，
	 * @param bv
	 */
	public void gotoRelogin(final BaseView bv) {
		// 清空全部poi
		BaseView.mid_.poiRepo_.removeAllActionPoi();
		try {
			// 执行登录界面
			um_.clientHello(bv);
		} catch (Exception e) {
			Utils.printException(e);
		}
	}
	
	/**
	 * Return the current top-level POI list view object. 
	 * Return the current POI selection object from the current POI list view object.
	 */
	public final PoiSelection getCurrentPoiSelection(boolean isTempSelection, BaseView activity) {
		if (poiRepo_.channel_ == null)
			return null;
		if (poiListSelection_ == null) {
			poiListSelection_ = new PoiListSelection(this);
		}
		poiListSelection_.setCurrentView(getDetailView(activity));
		return poiListSelection_;
	}
	
	public boolean checkUpdatesFromServer(PoiSelection poiSet, BaseView bv) {
		DisplayPoi poi = poiSet.getCurrentPOI();
		if (poi == null) {
			alert(activity_, "No POI is selected.", false);
			return false;
		}
		// 注意：在populate之前必须调用此处
		poi.poi_.checkUpdatesFromServer(this, bv);
		return true;
	}
}
